package com.idroc.storage.support;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.idroc.storage.IoBlock;
import com.idroc.storage.IoBlockFile;

/**
 * IO最小读写同步单位: IO块
 * @author yuyoo (yuyoo4j@163.com)
 * @date 2010-3-26 下午05:36:44
 */
public class FileIoBlock implements IoBlock {
	
	/**
	 * 日志记录器(logger)
	 */
	private static Logger logger = LoggerFactory.getLogger(FileIoBlock.class);
		
	/**
	 * 文件IO块大小
	 */
	private int size = 0;
	
	/**
	 * 本地IO块文件
	 */
	private LocalIoBlockFile file = null;
	
	/**
	 * IO块在文件中的偏移
	 */
	private long fileOffset = 0;
	
	/**
	 * IO块底层数据数组
	 */
	private byte[] backend = null;
	
	/**
	 * IO块在底层数据数组中的偏移
	 */
	private int backendOffset = 0;
	
	/**
	 * 是否是脏数据
	 */
	private boolean dirty = false;
	 	 
	/**
	 * 根据本地IO块文件和偏移位置构造IO块
	 * @param file -- 本地IO块文件
	 * @param fileOffset -- IO块文件中的偏移
	 * @param blockSize -- IO块大小
	 */
	public FileIoBlock(LocalIoBlockFile file, long fileOffset, int blockSize) {
		
		initialize(file, fileOffset, blockSize, new byte[size], 0);
	}
	
	/**
	 * 根据本地IO块文件和偏移位置与一个数组的区间构造IO块
	 * @param file -- 本地IO块文件
	 * @param fileOffset -- IO块文件中的偏移
	 * @param blockSize -- IO块大小
	 * @param backend -- 底层字节数组
	 * @param backendOffset -- 底层字节数组中的偏移
	 */
	public FileIoBlock(LocalIoBlockFile file, long fileOffset,  int blockSize, byte[] backend, int backendOffset) {

		initialize(file, fileOffset, blockSize, backend, backendOffset);
	}
 
	/**
	 * 初始化
	 * @param file -- 本地IO块文件
	 * @param fileOffset -- IO块文件中的偏移
	 * @param blockSize -- IO块大小
	 * @param backend -- 底层字节数组
	 * @param backendOffset -- 底层字节数组中的偏移
	 */
	protected void initialize(LocalIoBlockFile file, long fileOffset,  int blockSize, byte[] backend, int backendOffset) {

		this.file = file;
		this.fileOffset = fileOffset;
		this.size = blockSize;
		this.backend = backend;
		this.backendOffset = backendOffset;
	}
	
	/*
	 * 在IO分页中的位置
	 * @see com.idroc.storage.IoBlock#getOffset()
	 */
	public long getOffset() {
		
		return fileOffset;
	}

	/*
	 * 获取IO块文件
	 * @see com.idroc.storage.IoBlock#getIoBlockFile()
	 */
	public IoBlockFile getIoBlockFile() {
		
		return file;
	}

	/*
	 * 是否是脏数据块
	 * @see com.idroc.storage.IoBlock#isDirty()
	 */
	public boolean isDirty() {
		
		return dirty;
	}

	/*
	 * 重新从IO块文件中加载数据
	 * @see com.idroc.storage.IoBlock#load()
	 */
	public boolean load() {

		file.readData(fileOffset, backend, backendOffset, size);
		dirty = false;
		return true;
	}

	/*
	 * 读取一个字节
	 * @see com.idroc.storage.IoBlock#read(int)
	 */
	public byte read(int pos) {
		
		return backend[backendOffset + pos];
	}

	/*
	 * 读取一个字节数组
	 * @see com.idroc.storage.IoBlock#readBytes(int, int)
	 */
	public byte[] readBytes(int pos, int length) {

		byte[] d = new byte[length];
		System.arraycopy(backend, backendOffset, d, 0, length);
		return d;
	}

	/*
	 * 读取一个int
	 * @see com.idroc.storage.IoBlock#readInt(int)
	 */
	public int readInt(int pos) {

		int ch0 = backend[backendOffset + pos + 0];
		int ch1 = backend[backendOffset + pos + 1];
		int ch2 = backend[backendOffset + pos + 2];
		int ch3 = backend[backendOffset + pos + 3];
		
		return (ch0 << 24) + (ch1 << 16) + (ch2 << 8) + ch3;
	}

	/*
	 * 读取一个long
	 * @see com.idroc.storage.IoBlock#readLong(int)
	 */
	public long readLong(int pos) {
 
		return ((long)backend[backendOffset + pos + 0] << 56)
				+ ((long)(backend[backendOffset + pos + 1] & 255) << 48)
				+ ((long)(backend[backendOffset + pos + 2] & 255) << 40)
				+ ((long)(backend[backendOffset + pos + 3] & 255) << 32)
				+ ((long)(backend[backendOffset + pos + 4] & 255) << 24)
				+ ( (backend[backendOffset + pos + 5] & 255) << 16)
				+ ( (backend[backendOffset + pos + 6] & 255) << 8)
				+ ( (backend[backendOffset + pos + 7] & 255) << 0);
		
	}

	/*
	 * 读取一个short
	 * @see com.idroc.storage.IoBlock#readShort(int)
	 */
	public short readShort(int pos) {
		  
		int ch1 = backend[backendOffset + pos + 0];
	    int ch2 = backend[backendOffset + pos + 1];
		return (short)((ch1 << 8) + (ch2 << 0));
	}
	
	/*
	 * IO块大小
	 * @see com.idroc.storage.IoBlock#size()
	 */
	public int size() {

		return size;
	}

	/*
	 * 将IO块数据同步到IO块文件中
	 * @see com.idroc.storage.IoBlock#sync()
	 */
	public boolean sync() {

		if (dirty) {
			file.write(this);
			dirty = false;
		} 
		return true;
	}

	/*
	 * 写入一个字节
	 * @see com.idroc.storage.IoBlock#write(int, byte)
	 */
	public void write(int pos, byte value) {
		
		backend[backendOffset + pos] = value;
		dirty = true;
	}
	
	/*
	 * 写入一个字节数组
	 * @see com.idroc.storage.IoBlock#write(int, byte[])
	 */
	public void write(int pos, byte[] values) {

		logger.debug("backend:{}, backendOffset:{}", backend.length, backendOffset);
		logger.debug("pos:{}, values:{}", pos, values.length);
		System.arraycopy(values, 0, backend, backendOffset + pos, values.length);
		dirty = true;
	}

	/*
	 * 写入一个int
	 * @see com.idroc.storage.IoBlock#writeInt(int, int)
	 */
	public void writeInt(int pos, int value) {
		
		backend[backendOffset + pos + 0] = (byte)((value >>> 24) & 0xFF);
		backend[backendOffset + pos + 1] = (byte)((value >>> 16) & 0xFF);
		backend[backendOffset + pos + 2] = (byte)((value >>> 8) & 0xFF);
		backend[backendOffset + pos + 3] = (byte)((value >>> 0) & 0xFF);
		dirty = true;
	}

	/*
	 * 写入一个long
	 * @see com.idroc.storage.IoBlock#writeLong(int, long)
	 */
	public void writeLong(int pos, long value) {
		
		backend[backendOffset + pos + 0] = (byte)(value >>> 56);
		backend[backendOffset + pos + 1] = (byte)(value >>> 48);
		backend[backendOffset + pos + 2] = (byte)(value >>> 40);
		backend[backendOffset + pos + 3] = (byte)(value >>> 32);
		backend[backendOffset + pos + 4] = (byte)(value >>> 24);
		backend[backendOffset + pos + 5] = (byte)(value >>> 16);
		backend[backendOffset + pos + 6] = (byte)(value >>>  8);
		backend[backendOffset + pos + 7] = (byte)(value >>>  0);
		dirty = true;
	}

	/*
	 * 写入一个short
	 * @see com.idroc.storage.IoBlock#writeShort(int, short)
	 */
	public void writeShort(int pos, short value) {

		backend[backendOffset + pos + 0] = (byte)((value >>> 8) & 0xFF);
		backend[backendOffset + pos + 1] = (byte)((value >>> 0) & 0xFF);
		dirty = true;
	}

	/*
	 * 获取IO块的数据
	 * @see com.idroc.storage.IoBlock#array()
	 */
	public byte[] array() {
		 
		return backend;
	}
 
	/*
	 * IO块在数组中的偏移位置
	 * @see com.idroc.storage.IoBlock#arrayOffset()
	 */
	public int arrayOffset() { 
		
		return backendOffset;
	}

	/*
	 * 将字节数组的部分数据包装成一个IO块
	 * @see com.idroc.storage.IoBlock#wrap(byte[], int)
	 */
	public void wrap(byte[] data, int offset) {
		 
		backend = data;
		backendOffset = offset;
		dirty = false;
	}
	
	@Override
	public String toString() {

		StringBuilder sb = new StringBuilder(256);
		sb.append("FileIoBlock{");
		sb.append("file:").append(file).append(",");
		sb.append("fileOffset:").append(fileOffset).append(",");
		sb.append("size:").append(size).append(",");
		sb.append("backendOffset:").append(backendOffset).append(",");
		sb.append("dirty:").append(dirty).append(",");
		sb.append("}");
		
		return sb.toString();
	}
}
